#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include "snake.h"
#include <direct.h>
#include <mmsystem.h> 
#pragma comment(lib, "winmm.lib")
DWORD soundStateStartTime = 0;

#define MAX(a, b) ((a) > (b) ? (a) : (b))
bool isSoundEnabled = true; // 音效开关状态
int score = 0; // 当前得分
bool isPaused = false; // 游戏暂停状态
SnakeState snakeState; 
int highScore = 0; // 最高分
bool isGameRunning = true; // 游戏运行状态
bool isInGame = false; // 是否在游戏中
int speed = 300; // 游戏速度
TipMessage speedTip = { .message = "", .showTime = 0 };

int main(void)
{
    isGameRunning = true;
    mciSendString("open new type waveaudio alias output", NULL, 0, NULL);
    while (isGameRunning) {
        while (1) {
            hideCursor();
            welcometogame();
            while (_kbhit()) _getch();
            char choice = _getch();
            system("cls");
            switch (choice) {
            case '1': {
                srand((unsigned)time(NULL));
                initsnake();
                generatefood();
                score = 0;
                speed = 300;
                int t = speed;
                bool gameOver = false;
                isPaused = false;
                snake.direction = 'd';
                isInGame = true;
                gotoxy(0, HIGH + 3);
                printf("                    ");
                while (_kbhit()) _getch(); // 清空输入缓冲区

                while (isInGame && !gameOver) {
                    if (GetAsyncKeyState(VK_F1) & 0x8000) {
                        speed = MAX(speed - 20, 50);
                        gotoxy(0, HIGH + 3);
                        printf("加速至: %.2f格/秒  ", 1000.0f / speed);
                        Sleep(100);
                    }
                    if (GetAsyncKeyState(VK_F2) & 0x8000) {
                        speed += 20;
                        gotoxy(0, HIGH + 3);
                        printf("减速至: %.2f格/秒  ", 1000.0f / speed);
                        Sleep(100);
                    }
                    if (_kbhit()) {
                        int key = _getch();
                        if (key == 'p' || key == 'P') {
                            isPaused = !isPaused;
                        }
                        else if (!isPaused) {
                            handleInput(key); // 处理按键输入
                        }
                    }

                    if (!isPaused && isInGame) {
                        moveSnake();

                        // 吃食物检测
                        if (snake.body[0].X == food.X && snake.body[0].Y == food.Y) {
                            if (isSoundEnabled) {
                                mciSendString(L"close wave", 0, 0, 0);
                                mciSendString(L"open 1.mp3 alias wave", 0, 0, 0);
                                mciSendString(L"play wave", 0, 0, 0);
                            }
                            gotoxy(food.X, food.Y);
                            printf(" ");
                            // 计算得分
                            int speedDiff = 300 - speed;
                            int bonus = (speedDiff / 20) * 2;
                            int currentScore = 10 + bonus;
                            score += MAX(currentScore, 0);
                            // 增加蛇长度
                            Position newTail = snakeState.oldTail; 
                            snake.size++;
                            snake.body[snake.size - 1] = newTail; 

                            generatefood();
                            if (speed > 50) {  
                                speed -= 10;  
                            }
                        }

                        if (checkCollision()) {
                            if (isSoundEnabled) {
                                mciSendString(L"close ave", 0, 0, 0);
                                mciSendString(L"open 2.mp3 alias ave", 0, 0, 0);
                                mciSendString(L"play ave", 0, 0, 0);
                            }
                            gameOver = true;
                            gotoxy(WIDE / 2 - 5, HIGH / 2);
                            setColor(RED);
                            printf("游戏结束！得分：%d", score);
                            if (score > highScore) {
                                highScore = score;
                                File_out(); 
                                gotoxy(WIDE / 2 - 8, HIGH / 2 + 1);
                                printf("破纪录了！");
                            }
                            Sleep(2000);
                        }

                        drawGame();
                    }
                    Sleep(speed);
                }
                break;
            }
            case '2': // 显示最高分
                highScore = File_in();
                scoreandtips();
                system("pause");
                break;

            case '3': // 退出游戏
                printf("感谢游玩！");
                isGameRunning = false;
                mciSendString("close output", NULL, 0, NULL);
                Sleep(2000);
                return EXIT_SUCCESS;

            default:
                printf("无效选择！请输入1-3");
                system("pause");
                break;
            }
        }
    }
    mciSendString("close output", NULL, 0, NULL);
    return EXIT_SUCCESS;
}

// 读取最高分文件
int File_in(void) {
    FILE* file = fopen("high_score.txt", "r");
    if (!file) return 0; 

    int score;
    fscanf(file, "%d", &score);
    fclose(file);
    return score;
}

// 保存最高分文件
void File_out(void) {
    FILE* file = fopen("high_score.txt", "w");
    if (!file) return;
    fprintf(file, "%d", highScore);
    fclose(file);
}

// 显示最高分及提示信息
void scoreandtips(void) {
    system("cls"); 
    setColor(YELLOW);

    gotoxy(WIDE / 2 - 8, 5); 
    printf("==== 最高分记录 ====");

    gotoxy(WIDE / 2 - 8, 7);
    printf("当前最高分：%d", highScore);

    setColor(WHITE);
    gotoxy(WIDE / 2 - 9, 9); 
    printf("按任意键返回主菜单"); 

    _getch(); 
}

// 初始化蛇
void initsnake(void)
{
    snake.direction = 'd';
    snake.size = 2;
    snake.body[0].X = WIDE / 2;
    snake.body[0].Y = HIGH / 2;
    snake.body[1].X = WIDE / 2 - 1;
    snake.body[1].Y = HIGH / 2;
    snakeState.oldTail = snake.body[1];
    initUI();
    return;
}

// 处理按键输入
void handleInput(int key) {
    switch (key) {
    case 'W':
    case 'w':
    case VK_UP:
        if (snake.direction != 's') snake.direction = 'w';
        break;
    case 'S':
    case 's':
    case VK_DOWN:
        if (snake.direction != 'w') snake.direction = 's';
        break;
    case 'A':
    case 'a':
    case VK_LEFT:
        if (snake.direction != 'd') snake.direction = 'a';
        break;
    case 'D':
    case 'd':
    case VK_RIGHT:
        if (snake.direction != 'a') snake.direction = 'd';
        break;
    case VK_ESCAPE:
        isInGame = false;
        break;
    case VK_F1: {
        int newSpeed = MAX(speed - 20, 50);
        if (newSpeed != speed) {
            speed = newSpeed;
            snprintf(speedTip.message, 50, "加速至: %.2f格/秒", 1000.0f / speed);
            speedTip.showTime = GetTickCount() + 2000; 
        }
        break;
    }
    case VK_F2: {
        int newSpeed = speed + 20;
        if (newSpeed != speed) {
            speed = newSpeed;
            snprintf(speedTip.message, 50, "减速至: %.2f格/秒", 1000.0f / speed);
            speedTip.showTime = GetTickCount() + 2000; 
        }
        break;
    }
    case 'E':
    case 'e':
        soundStateStartTime = GetTickCount();
        isSoundEnabled = !isSoundEnabled;
        gotoxy(0, HIGH + 4);
        setColor(YELLOW);
        printf("音效状态：%s", isSoundEnabled ? "开启" : "关闭");
        gotoxy(0, HIGH + 4);
        printf("                    "); 
        break;

    default:
        break;
    }
}

// 获取蛇头方向对应的字符表示
char* SnakeHead(char direction) {
    switch (direction) {
    case 'w': return "^";  
    case 's': return "v";  
    case 'a': return "<";  
    case 'd': return ">";  
    default:  return "+";  
    }
}

// 初始化游戏界面
void initUI(void)
{
    setColor(WHITE);
    for (int y = 0; y < HIGH; y++) {
        gotoxy(WIDE, y);
        printf("■");
    }
    for (int x = 0; x <= WIDE; x++) {
        gotoxy(x, HIGH);
        printf("■");
    }
    gotoxy(0, HIGH + 1);
    printf("得分: 0");
    setColor(WHITE);
}

// 设置控制台文本颜色
void setColor(int color) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, color);
}

// 设置控制台光标位置
void gotoxy(int x, int y) {
    COORD coord = { x, y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 隐藏控制台光标
void hideCursor() {
    CONSOLE_CURSOR_INFO cursorInfo = { 1, 0 };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo);
}

// 绘制欢迎界面
void welcometogame() {
    system("cls");
    SetConsoleTitle("贪吃蛇游戏");
    gotoxy(10, 5); setColor(RED);
    printf("╭───╮");
    gotoxy(10, 6);
    printf("│ ◎ ╰ ");
    gotoxy(10, 7);
    printf("│ ◎ ╭");
    gotoxy(10, 8);
    printf("╰───╯");
    int bodyX = 16;
    const char* bodyLines[] = {
        "      ╭──────╮",
        "───╮  │ ╭──╮ │  ╭─────╮__",
        "─╮ │  │ │  │ │  │  ╭──╯ ",
        " │ ╰──╯ │  │ ╰──╯  │ ",
        " ╰──────╯  ╰───────╯"
    };
    for (int i = 0; i < 5; i++) {
        gotoxy(bodyX, 5 + i);
        setColor(GREEN);
        printf("%s", bodyLines[i]);
    }
    gotoxy(20, 15); setColor(MAGENTA); printf("欢迎来到贪吃蛇游戏");
    gotoxy(18, 18); setColor(WHITE); printf("使用 WASD 控制蛇的移动");
    gotoxy(18, 19); setColor(WHITE); printf("按 P 键暂停游戏 按E开启/关闭音效");
    gotoxy(20, 22); setColor(YELLOW); printf("按 1 进入游戏");
    gotoxy(20, 23); setColor(YELLOW); printf("按 2 显示最高分");
    gotoxy(20, 24); setColor(YELLOW); printf("按 3 退出游戏");
    setColor(WHITE);
}

// 绘制游戏画面
void drawGame(void)
{
    // 清除旧蛇尾
    gotoxy(snakeState.oldTail.X, snakeState.oldTail.Y);
    printf(" ");
    // 绘制蛇头
    gotoxy(snake.body[0].X, snake.body[0].Y);
    setColor(RED);
    printf("%s", SnakeHead(snake.direction));
    // 绘制蛇身
    for (int i = 1; i < snake.size; i++) {
        gotoxy(snake.body[i].X, snake.body[i].Y);
        setColor(GREEN);
        printf("X");
    }
    // 绘制食物
    gotoxy(food.X, food.Y);
    setColor(WHITE);
    printf("●");
    // 得分显示
    gotoxy(0, HIGH + 1);
    setColor(RED);
    printf("得分: %-5d", score); 
    // 速度显示
    gotoxy(0, HIGH + 2);
    setColor(BLUE);
    printf("速度: %-7.2f格/秒", 1000.0f / speed);
    // 音效状态显示
    gotoxy(WIDE - 15, HIGH + 1);
    setColor(isSoundEnabled ? GREEN : RED);
    printf("[音效:%s]", isSoundEnabled ? "ON " : "OFF");

    // 提示信息
    gotoxy(0, HIGH + 3);
    setColor(YELLOW);
    if (GetTickCount() < speedTip.showTime) {
        printf("%-50s", speedTip.message);
    }
    else {
        printf("%-50s", " ");
    }

    // 音效状态提示显示
    gotoxy(0, HIGH + 4);
    if (GetTickCount() - soundStateStartTime < 1000) {
        setColor(YELLOW);
        printf("音效状态：%s", isSoundEnabled ? "开启" : "关闭");
    }
    else {
        printf("                    "); 
    }
    // 强制刷新缓冲区
    fflush(stdout);
}

// 移动蛇
void moveSnake()
{
    // 保存旧蛇尾
    if (snake.size > 0) {
        snakeState.oldTail = snake.body[snake.size - 1];
    }

    // 移动身体
    for (int i = snake.size - 1; i > 0; i--) {
        snake.body[i] = snake.body[i - 1];
    }

    // 移动头部
    switch (snake.direction) {
    case 'w': snake.body[0].Y--; break;
    case 's': snake.body[0].Y++; break;
    case 'a': snake.body[0].X--; break;
    case 'd': snake.body[0].X++; break;
    }
}

// 检查碰撞
bool checkCollision()
{
    if (snake.body[0].X < 0 || snake.body[0].X >= WIDE ||
        snake.body[0].Y < 0 || snake.body[0].Y >= HIGH) {
        return true;
    }

    for (int i = 1; i < snake.size; i++) {
        if (snake.body[0].X == snake.body[i].X &&
            snake.body[0].Y == snake.body[i].Y) {
            return true;
        }
    }
    return false;
}

// 生成食物
void generatefood() {
    gotoxy(food.X, food.Y);
    printf(" ");
    do {
        food.X = rand() % WIDE;
        food.Y = rand() % HIGH;
    } while (!isFoodValid());
    gotoxy(food.X, food.Y);
    setColor(WHITE);
    printf("●");
}

// 检查食物生成位置是否有效
bool isFoodValid() {
    if (food.X >= WIDE - 1 || food.Y >= HIGH - 1) return false;
    for (int i = 0; i < snake.size; i++) {
        if (food.X == snake.body[i].X &&
            food.Y == snake.body[i].Y) {
            return false;
        }
    }
    return true;
}